#include <fs.h>
#include <device.h>
#include <debug.h>
#include <string.h>

#include <sched.h>
#include <errors.h>

// Discos
#include <fdd.h>
#include <hdd.h>

// Sistemas de archivos
#include <fat12.h>
#include <fat16.h>

// Dispositivos
#include <serial.h>
#include <con.h>

//Pipes
#include <pipe.h>

/*
 * Disco 1;
 */ 
fat16 fat16_disk;
int fat16_inicializada;

/*
 * Se pueden agregar más discos así:
 */
 //~ fat16 disk2; 
 //~ fat32 disk3;
 //~ ext2 disk4;
 //~ resiserfs disk5;
 //~ ntfs disk6;

void fs_init(void) {
	/* Inicializar los dispositivos (ojo con las llamadas bloqueantes) */
	// Ejemplo: fat12_create(&disk, fdd_open(0));
	// Ejemplo: fat16_create(&disk2, hdd_open(0));
	
	device_init();

	con_init();

	serial_init();

	hdd_init();

	pipe_init();

	fat16_inicializada = 0;

	//fat16_create(&disk, hdd_open(0));
}

//Funcion de FS para abrir un pipe
int fs_pipe_open(int *pipes) {

	int r_fd, w_fd;
	chardev *devpipes[2];

	if (pipe_open(devpipes)) {
		return -ENOPIPE;
	}

 	r_fd = device_descriptor(devpipes[0]);
 	w_fd = device_descriptor(devpipes[1]);

	pipes[0] = r_fd;
	pipes[1] = w_fd;
	
	return 0;
}

//Funcion generica para abrir
chardev* fs_open(const char* filename, uint_32 flags) {

	chardev *dev = NULL;

	/* Checkea el pedido de apertura como lectura o escritura */
	if ((flags & FS_OPEN_RDWR) == 0) return NULL; /* Pedido frutero */
	

	if (!strcmp(filename, "/serial0")) dev = serial_open(0);
	if (!strcmp(filename, "/serial1")) dev = serial_open(1);
	if (!strcmp(filename, "/console")) dev = con_open(); 

	/*
	 * Pedido para el disco 1: Usamos fat12 para abrirlo
	 */ 
	if (!strncmp(filename, "/disk/", 6)) {
		
		if (!fat16_inicializada) {
			fat16_create(&fat16_disk, hdd_open(0));
		}
		
		dev = fat16_open(&fat16_disk, filename+5, flags);
		
	}
	
	if (NULL == dev)
		return NULL;

	//segun los flags seteo el null lo que corresponda
	switch(flags) {
		case FS_OPEN_RDONLY:
			dev->write = NULL;
		break;
		case FS_OPEN_WRONLY:
			dev->read = NULL;
	}

	return dev;
}

// Syscalls:
int open(const char* filename, uint_32 flags) {

	chardev * new_chardev;
	int new_fd;

	//obtengo un chardev
	new_chardev = fs_open(filename, flags);
	if (NULL == new_chardev) {
		return -ENOCHARDEV;
	}

	//obtengo un fd
	new_fd = device_descriptor(new_chardev); 
	if (new_fd < 0) {
		new_chardev->flush(new_chardev);
		return new_fd;
	}

	//retorno el fd
	return new_fd;
}

